﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using WHW_NetUtility;

namespace MainFrame
{
    public class opencvProc
    {
        /// <summary>
        /// 读入灰度图像
        /// </summary>
        /// <param name="path">图像存放路径</param>
        /// <returns>图像对应的mat</returns>
        public static Mat readImage(string path)
        {
            try
            {
                Mat temp = null;
                temp= Cv2.ImRead(path, ImreadModes.Grayscale);
                return temp;
            }
            catch (System.Exception ex)
            {
                Log4Helper.WriteLog("opencvProc.readImage", ex);
                return null;
            }

        }
        public static Mat Flip(Mat input, int flag)
        {
            try
            {
                Mat temp = new Mat();
                switch (flag)
                {
                    case -1:
                        Cv2.Flip(input, temp, FlipMode.XY);
                        break;
                    case 0:
                        Cv2.Flip(input, temp, FlipMode.X);
                        break;
                    case 1:
                        Cv2.Flip(input, temp, FlipMode.Y);
                        break;
                    default:
                        temp = input;
                        break;
                }
                return temp;
            }
            catch (System.Exception ex)
            {
                Log4Helper.WriteLog("opencvProc.Flip", ex);
                return null;
            }
            
        }
        public static Mat Flip(Mat input, bool Xflip,bool Yflip)
        {
            if (input==null)
            {
                Log4Helper.WriteLog("opencvProc.Flip", "输入Mat不能为空");
                return null;
            }
            try
            {
                Mat temp = new Mat();
                if (Xflip&&(!Yflip))
                {
                    Cv2.Flip(input, temp, FlipMode.X);
                }
                else if ((!Xflip)&&Yflip)
                {
                    Cv2.Flip(input, temp, FlipMode.Y);
                }
                else if (Xflip&&Yflip)
                {
                    Cv2.Flip(input, temp, FlipMode.XY);
                }
                else
                {
                    temp = input;
                }
                return temp;
            }
            catch (System.Exception ex)
            {
                Log4Helper.WriteLog("opencvProc.Flip", ex);
                return null;
            }

        }
        /// <summary>
        /// 保存图像
        /// </summary>
        /// <param name="input">输入的图像Mat</param>
        /// <param name="path">要保存的路径</param>
        public static void saveImage(Mat input, string path)
        {
            try
            {
                if (!string.IsNullOrEmpty(path))
                {
                    Cv2.ImWrite(path, input);
                    displalyInfo.displayInfoMain("图像保存成功");
                }
                else
                {
                    displalyInfo.displayInfoMain("保存路径不能为空！");
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("图像保存失败，原因："+ex.Message);
            }
        }

        /// <summary>
        /// 查找圆轮廓
        /// </summary>
        /// <param name="input">输入图像Mat</param>
        /// <param name="OnlyExternal">是否只查找外轮廓</param>
        /// <param name="minContour">轮廓最小值</param>
        /// <param name="maxContour">轮廓最大值</param>
        /// <param name="circleError">查找的轮廓长轴和短轴差值，小于给定值的，认为是圆，否则为椭圆</param>
        /// <param name="center">查找的圆列表，包括半径，中心XY</param>
        public static void FindCircle(Mat input,bool OnlyExternal,int minContour,
                                        int maxContour,int circleError,ref List<double[]> center)
        {
            try
            {

                OpenCvSharp.Point[][] contours;
                HierarchyIndex[] hier;
                RotatedRect centerCicle;
                List<RotatedRect> findCenters=new List<RotatedRect>();
                //Moments _moment;
                if (input==null)
                {
                    displalyInfo.displayInfoMain("输入Mat不能为空");
                    return;
                }
                Cv2.MedianBlur(input, input, 3);//中值滤波
                Cv2.Threshold(input, input, 90, 250, ThresholdTypes.BinaryInv);//二值化
                if (OnlyExternal)
                {
                    Cv2.FindContours(input, out contours, out hier, RetrievalModes.External, ContourApproximationModes.ApproxNone);
                }
                else
                {
                    Cv2.FindContours(input, out contours, out hier, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
                }
                if (minContour<=0||minContour>maxContour)
                {
                    displalyInfo.displayInfoMain("要去除的轮廓下限必须大于0且小于上限");
                    return;
                }
                for (int i=0;i<contours.Length;i++)
                {
                    double areaTemp = Cv2.ContourArea(contours[i]);
                    //_moment= Cv2.Moments(contours[i],false);
                    //_moment.HuMoments();//hu矩，返回是一个double数组
                    if (areaTemp<minContour||areaTemp>maxContour)
                    {
                        Cv2.DrawContours(input, contours, i, Scalar.All(0), 10);
                    }
                    else
                    {
                        //Cv2.DrawContours(input, contours, i, Scalar.All(120), 10);
                        centerCicle = Cv2.FitEllipse(contours[i]);
                        findCenters.Add(centerCicle);
                        
                    }
                }

                //displalyInfo.displayInfoMain("共找到： "+findCenters.Count.ToString()+" 个圆（椭圆）");

                for (int i=0;i<findCenters.Count;i++)
                {
                    if (Math.Abs(findCenters[i].Size.Height-findCenters[i].Size.Width)<circleError )
                    {
                        double r = (findCenters[i].Size.Height + findCenters[i].Size.Width) / 2;
                        center.Add(new double[3] { findCenters[i].Center.X, findCenters[i].Center.Y,r });
                        Cv2.Circle(input, (int)findCenters[i].Center.X, (int)findCenters[i].Center.Y, (int)r / 10, Scalar.All(120), 10);
                    }
                }
                //displalyImage.displayImage_F(input);
                displalyInfo.displayInfoMain("共找到： " + findCenters.Count.ToString() + " 个（圆+椭圆） " + "其中有： " + center.Count.ToString() + " 个圆");
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("opencvProc.FindCircle 出错："+ex.Message);
            }

        }

        /// <summary>
        /// 根据输入中心点坐标及宽高生成矩形ROI
        /// </summary>
        /// <param name="centerX">ROI中心X</param>
        /// <param name="centerY">ROI中心Y</param>
        /// <param name="width">ROI宽</param>
        /// <param name="height">ROI高</param>
        /// <returns>返回生成的矩形ROI</returns>
        public static Rect CenterRectRoi(int centerX,int centerY,int width,int height)
        {
            Rect centerRect=new Rect();
            try
            {
                int startleft = centerX - width / 2;
                int startUp = centerY - height / 2;
                if (startUp < 0)
                {
                    startUp = 0;
                }
                if (startleft < 0)
                {
                    startleft = 0;
                }

                centerRect = new Rect(startleft,startUp,width,height);
                return centerRect;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("centerRectRoi 出错："+ex.Message);
                return centerRect;
            }
        }


        /// <summary>
        /// 查找焊点中心位置
        /// </summary>
        /// <param name="input">输入的mat</param>
        /// <param name="output">输出的mat,可用于显示</param>
        /// <param name="roi">要查找焊点的ROI，数组分别代表 中心X，中心Y，ROI宽，ROI高</param>
        /// <param name="thresholdL">手动阈值低</param>
        /// <param name="thresholdH">手动阈值高</param>
        /// <param name="contourLength">轮廓长度范围数组分别为 首次查找的长度低值、长度高值，二次查找的长度低值，长度高值</param>
        /// <param name="weldPoint">焊点尺寸 数组代表 焊点宽，焊点高</param>
        public static void findWeldPoint(Mat input,ref Mat output, int[] roi,int thresholdL,int thresholdH,int[] contourLength,int[] weldPoint)
        {
            Mat roiMat;
            OpenCvSharp.Rect recRoi = CenterRectRoi(roi[0],roi[1],roi[2],roi[3]);
            roiMat = new Mat(input, recRoi);
            output = input.Clone();
            OpenCvSharp.Size wholesize;
            OpenCvSharp.Point ofs;
            RotatedRect m = new RotatedRect();
            roiMat.LocateROI(out wholesize, out ofs);

            Cv2.Threshold(roiMat, roiMat, thresholdL, thresholdH, ThresholdTypes.BinaryInv);
            Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(11, 11));
            Cv2.MorphologyEx(roiMat, roiMat, MorphTypes.Open, element);
            //Mat roiMatCopy = roiMat.Clone();
            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hier;
            Cv2.FindContours(roiMat, out contours, out hier, RetrievalModes.Tree, ContourApproximationModes.ApproxNone, ofs);
            Cv2.CvtColor(roiMat, roiMat, ColorConversionCodes.GRAY2RGB);
            //Cv2.CvtColor(imageMat, imageMat, ColorConversionCodes.GRAY2RGB);
            if (contours.Length != 0)
            {
                for (int i = 0; i < contours.Length; i++)
                {
                    if (contours[i].Length > contourLength[0] && contours[i].Length < contourLength[1])
                    {
                        Cv2.DrawContours(input, contours, i, Scalar.Red, 8, LineTypes.Link8);//画轮廓的时候，不用加偏移
                        m = Cv2.MinAreaRect(contours[i]);
                        //messageDisplay("X：" + (m.Points()[0]).X.ToString() + "  Y：" + (m.Points()[0]).Y.ToString());
                        //Cv2.DrawContours(imageMat, contours, i, Scalar.Red, 8, LineTypes.Link8);//画轮廓的时候，不用加偏移
                        Cv2.Line(input, (int)(m.Points())[0].X, (int)(m.Points())[0].Y,
                            (int)(m.Points())[1].X, (int)(m.Points())[1].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(input, (int)(m.Points())[0].X, (int)(m.Points())[0].Y,
                            (int)(m.Points())[3].X, (int)(m.Points())[3].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(input, (int)(m.Points())[1].X, (int)(m.Points())[1].Y,
                            (int)(m.Points())[2].X, (int)(m.Points())[2].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(input, (int)(m.Points())[2].X, (int)(m.Points())[2].Y,
                            (int)(m.Points())[3].X, (int)(m.Points())[3].Y, Scalar.OrangeRed, 5);
                    }

                }

            }
            if (m.Points()[0].X == 0.0 && m.Points()[2].X == 0.0)
            {
                return;
            }
            Point2f[] my = m.Points();
            OpenCvSharp.Rect NewRoi = new OpenCvSharp.Rect((int)m.Points()[1].X, (int)m.Points()[1].Y, weldPoint[0], weldPoint[1]);
            Mat roiMatcopy = new Mat(output, NewRoi);

            OpenCvSharp.Size wholesize1;
            OpenCvSharp.Point ofs1;
            RotatedRect m1 = new RotatedRect();
            roiMatcopy.LocateROI(out wholesize1, out ofs1);
            if (thresholdL>20)
            {
                Cv2.Threshold(roiMatcopy, roiMatcopy, thresholdL - 20, thresholdH, ThresholdTypes.BinaryInv);
            }
            else
            {
                Cv2.Threshold(roiMatcopy, roiMatcopy, thresholdL, thresholdH, ThresholdTypes.BinaryInv);
            }
           
            Cv2.MorphologyEx(roiMatcopy, roiMatcopy, MorphTypes.Open, element);

            Cv2.FindContours(roiMatcopy, out contours, out hier, RetrievalModes.Tree, ContourApproximationModes.ApproxNone, ofs1);
            Cv2.CvtColor(roiMatcopy, roiMatcopy, ColorConversionCodes.GRAY2RGB);
            Cv2.CvtColor(output, output, ColorConversionCodes.GRAY2RGB);
            if (contours.Length != 0)
            {
                for (int i = 0; i < contours.Length; i++)
                {
                    if (contours[i].Length > contourLength[2] && contours[i].Length < contourLength[3])
                    {
                        Cv2.DrawContours(output, contours, i, Scalar.Red, 8, LineTypes.Link8);//画轮廓的时候，不用加偏移
                        m1 = Cv2.MinAreaRect(contours[i]);
                        //messageDisplay("X：" + (m1.Points()[1]).X.ToString() + "  Y：" + (m1.Points()[1]).Y.ToString());
                        //Cv2.DrawContours(imageMat, contours, i, Scalar.Red, 8, LineTypes.Link8);//画轮廓的时候，不用加偏移
                        Cv2.Line(output, (int)(m1.Points())[0].X, (int)(m1.Points())[0].Y,
                            (int)(m1.Points())[1].X, (int)(m1.Points())[1].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(output, (int)(m1.Points())[0].X, (int)(m1.Points())[0].Y,
                            (int)(m1.Points())[3].X, (int)(m1.Points())[3].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(output, (int)(m1.Points())[1].X, (int)(m1.Points())[1].Y,
                            (int)(m1.Points())[2].X, (int)(m1.Points())[2].Y, Scalar.OrangeRed, 5);
                        Cv2.Line(output, (int)(m1.Points())[2].X, (int)(m1.Points())[2].Y,
                            (int)(m1.Points())[3].X, (int)(m1.Points())[3].Y, Scalar.OrangeRed, 5);
                    }

                }

            }
        }

        /// <summary>
        /// 阈值处理（二值化）
        /// </summary>
        /// <param name="input">输入图像Mat</param>
        /// <param name="thresholdL">阈值低</param>
        /// <param name="thresholdH">阈值高</param>
        /// <param name="medianBlur">中值滤波核尺寸</param>
        /// <param name="gauss">高斯滤波核尺寸</param>
        /// <returns>处理成功返回true，否则返回false</returns>

        public static bool ThresholdImage(Mat input,uint thresholdL,uint thresholdH,uint medianBlur,uint gauss)
        {
            try
            {
                Cv2.MedianBlur(input, input, (int)medianBlur);
                Cv2.GaussianBlur(input, input, new OpenCvSharp.Size(gauss, gauss), 1);
                Cv2.Threshold(input, input, thresholdL, thresholdH, ThresholdTypes.BinaryInv);
                Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(7, 7));
                //Cv2.MorphologyEx(roiMat, roiMat, MorphTypes.Open, element);
                Cv2.MorphologyEx(input, input, MorphTypes.Open, element);
                //Cv2.PyrDown(input, input);
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("ThresholdImage 二值化出错："+ex.Message);
                return false;
            }

        }
        /// <summary>
        /// 二值化图像
        /// </summary>
        /// <param name="input">输入图像</param>
        /// <param name="thresholdL">阈值低</param>
        /// <param name="thresholdH">阈值高</param>
        /// <param name="medianBlur">中值滤波核大小</param>
        /// <param name="gauss">高斯滤波核大小</param>
        /// <param name="mt">形状学类型</param>
        /// <returns>成功返回true，否则返回false</returns>
        public static bool ThresholdImage(Mat input, uint thresholdL, uint thresholdH, uint medianBlur, uint gauss,MorphTypes mt)
        {
            try
            {
                Cv2.MedianBlur(input, input, (int)medianBlur);//中值滤波
                Cv2.GaussianBlur(input, input, new OpenCvSharp.Size(gauss, gauss), 1);//高斯滤波
                Cv2.Threshold(input, input, thresholdL, thresholdH, ThresholdTypes.BinaryInv);//二值化
                Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(7, 7));//结构元素
                Cv2.MorphologyEx(input, input, mt, element);//形态学处理
                //Cv2.PyrDown(input, input);
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("ThresholdImage 二值化出错：" + ex.Message);
                return false;
            }

        }

        /// <summary>
        /// 二值化图像,中值核3，高斯核7，形状学为开
        /// </summary>
        /// <param name="input">输入图像</param>
        /// <param name="thresholdL">阈值低</param>
        /// <param name="thresholdH">阈值高</param>
        /// <returns>成功返回true，否则返回false</returns>
        public static bool ThresholdImage(Mat input, uint thresholdL, uint thresholdH)
        {
            try
            {
                Cv2.MedianBlur(input, input, 3);
                Cv2.GaussianBlur(input, input, new OpenCvSharp.Size(7, 7), 1);
                Cv2.Threshold(input, input, thresholdL, thresholdH, ThresholdTypes.BinaryInv);
                Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(7, 7));
                Cv2.MorphologyEx(input, input, MorphTypes.Open, element);
                //Cv2.PyrDown(input, input);
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("ThresholdImage 二值化出错：" + ex.Message);
                return false;
            }

        }
        public static bool MatchTemplate(Mat input,Mat template,int pyramidLevel,double score,ref double[] result )
        {
            try
            {
                Mat resultM = new Mat();//匹配结果Mat
                Mat inputCopy = input.Clone();//要查找的Mat备份
                Mat templateCopy = template.Clone();//模板备份
                double min;//极小值
                double max;//极大值
                OpenCvSharp.Point minloc;
                OpenCvSharp.Point maxloc;
                //金字塔取样
                if (pyramidLevel<=1||pyramidLevel>5)
                {
                    pyramidLevel = 2;
                }
                for (int i=0;i<pyramidLevel-1;i++)
                {
                    Cv2.PyrDown(templateCopy, templateCopy);
                    Cv2.PyrDown(inputCopy ,inputCopy);
                }
                Cv2.MatchTemplate(inputCopy, templateCopy, resultM, TemplateMatchModes.CCoeffNormed);
                //Cv2.MinMaxLoc(resultM, out min, out max, out minloc, out maxloc);
                for (int i=0;i<pyramidLevel-1;i++)
                {
                    Cv2.PyrUp(resultM, resultM);
                }
                Cv2.MinMaxLoc(resultM, out min, out max, out minloc, out maxloc);
                if (Math.Abs(max)>=score)
                {
                    result[0] = Math.Abs(max);
                    result[1] = maxloc.X;
                    result[2] = maxloc.Y;
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("MatchTemplate 出错："+ex.Message);
                result = null;
                return false;
            }
        }

        public static bool PositionAdjust(Mat input,Mat output, double[] contoursLimit,float[] center,bool isDisplayContous,ref double[] minRectOutline)
        {
            try
            {
                if (input == null)
                {
                    return false;
                }
                double angleHor = 0;
                Point2f cirCenter = new Point2f(0, 0);
                //double[] minRectOutline = new double[2];
                //Mat inputMat = input.Clone();
                Mat rotateMat = new Mat(input.Size(), input.Type());

                Point2f newpoint = new Point2f(0, 0);
                if (position(input, ref angleHor, ref cirCenter,contoursLimit,isDisplayContous,ref minRectOutline))
                {
                    Mat angleM = Cv2.GetRotationMatrix2D(new Point2f(input.Width / 2, input.Height / 2), -angleHor, 1);
                    Cv2.WarpAffine(input, input, angleM, input.Size());
                    Cv2.WarpAffine(output, output, angleM, output.Size());
                    newpoint = getAffinedPoint(cirCenter, new Point2f(input.Width / 2, input.Height / 2), -angleHor);
                    float[,] tranF = new float[,] { { 1, 0, center[0] - newpoint.X }, { 0, 1, center[1] - newpoint.Y } };
                    Mat tranMat = new Mat(2, 3, MatType.CV_32FC1, tranF);
                    Cv2.WarpAffine(input, input, tranMat, input.Size());
                    Cv2.WarpAffine(output, output, tranMat, output.Size());
                    displalyInfo.displayInfoMain("平移坐标 X:" + ((center[0] - newpoint.X)/GlobalImage.cablibData_Measure.pixPerReal).ToString("#0.00") + "   Y:" + ((center[1] - newpoint.Y) / GlobalImage.cablibData_Measure.pixPerReal).ToString("#0.00"));

                }
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("PositionAdjust 错误："+ex.Message);
                return false;
            }
        }
        public static Point2f getAffinedPoint(Point2f oriPoint, Point2f center, double angle)
        {
            double anglePi = Math.PI * angle / 180;
            Point2f newPoint;
            float x = oriPoint.X - center.X;
            float y = oriPoint.Y - center.Y;
            newPoint.X = x * (float)Math.Cos(anglePi) + y * (float)Math.Sin(anglePi) + center.X;
            newPoint.Y = -x * (float)Math.Sin(anglePi) + y * (float)Math.Cos(anglePi) + center.Y;
            return newPoint;
        }

        public static bool position(Mat input, ref double RotateAngle, ref OpenCvSharp.Point2f cir_Center,double[] contoursLimit,bool isDisplayContours,ref double[] minRectOutline)
        {
            if (input==null)
            {
                return false;
            }
            Mat copyMat = input.Clone();
            bool XcorZero = false;
            bool YcorZero = false;
            bool haveRec = false;
            Point2f recCenter = new Point2f(0, 0);
            Point2f circleCenter = new Point2f(0, 0);
            double angleHor = 0;
            Mat labels = new Mat();
            Mat stats = new Mat();
            Mat centroids = new Mat();
            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hier;
            string displayContours = "";
            try
            {
                Cv2.FindContours(input, out contours, out hier, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
                if (isDisplayContours)
                {
                    for (int i=0;i<contours.Length;i++)
                    {
                        displayContours += (contours[i].Length/GlobalImage.cablibData_Measure.pixPerReal).ToString("#0.00")+" / ";
                    }
                    displalyInfo.displayInfoMain("轮廓大小为："+displayContours);
                }
                for (int i = 0; i < contours.Length; i++)
                {
                    if (contours[i].Length < contoursLimit[0] || contours[i].Length > contoursLimit[1])
                    { 
                        Cv2.DrawContours(input, contours, i, Scalar.All(0), 10);
                    }
                    else
                    {
                        haveRec = true;
                        Cv2.DrawContours(input, contours, i, Scalar.All(125), 10);
                        Point2d[] contour_d = new Point2d[contours[i].Length];
                        for (int m = 0; m < contours[i].Length; m++)
                        {
                            contour_d[m].X = (double)(contours[i][m].X);
                            contour_d[m].Y = (double)(contours[i][m].Y);
                        }
                        //double angleD = getOrientation(contour_d, imageMat);
                        //messageDisplay("偏转角度是：" + angleD.ToString());
                        RotatedRect minRect = Cv2.MinAreaRect(contours[i]);

                        recCenter = minRect.Center;
                        Point2f[] minRectPointsF = minRect.Points();

                        Point2f edge1 = new Point2f(minRectPointsF[1].X - minRectPointsF[0].X, minRectPointsF[1].Y - minRectPointsF[0].Y);
                        Point2f edge2 = new Point2f(minRectPointsF[2].X - minRectPointsF[1].X, minRectPointsF[2].Y - minRectPointsF[1].Y);
                        // 
                        //Vec2f edge1 = new Vec2f(minRectPoints[1].X - minRectPoints[0].X, minRectPoints[1].Y - minRectPoints[0].Y);
                        //Vec2f edge2 = new Vec2f(minRectPoints[2].X - minRectPoints[1].X, minRectPoints[2].Y - minRectPoints[1].Y);
                        Point2f useEdge = edge1;
                        if (Math.Sqrt(edge2.X * edge2.X + edge2.Y * edge2.Y) > Math.Sqrt(edge1.X * edge1.X + edge1.Y * edge1.Y))
                        {
                            useEdge = edge2;
                        }
                        Point2f refpoint = new Point2f(1, 0);//水平边缘

                        angleHor = 180.0f / Cv2.PI * Math.Acos((refpoint.X * useEdge.X + refpoint.Y * useEdge.Y) / Math.Sqrt(useEdge.X * useEdge.X + useEdge.Y * useEdge.Y));
                        displalyInfo.displayInfoMain("与水平的夹角：" + angleHor.ToString("#0.00"));
                        displalyInfo.displayInfoMain("最小外接矩形求出的角度" + minRect.Angle.ToString("#0.00"));

                        Moments contourMoments = Cv2.Moments(contours[i], false);

                        Point2d centerMom = new Point2d(contourMoments.M10 / contourMoments.M00, contourMoments.M01 / contourMoments.M00);
                        double a = contourMoments.M20 / contourMoments.M00 - centerMom.X * centerMom.X;
                        double b = contourMoments.M11 / contourMoments.M00 - centerMom.X * centerMom.Y;
                        double c = contourMoments.M02 / contourMoments.M00 - centerMom.Y * centerMom.Y;
                        double theta = Cv2.FastAtan2(2 * (float)b, (float)(a - c)) / 2;
                        RotateAngle = theta;
                        displalyInfo.displayInfoMain("轮廓角度是：" + theta.ToString("#0.00"));
                        //MinRect.BoundingRect();
                        OpenCvSharp.Point2f[] minRectPoints = minRect.Points();
                        Cv2.Line(input, (int)minRectPoints[0].X, (int)minRectPoints[0].Y,
                            (int)minRectPoints[1].X, (int)minRectPoints[1].Y, Scalar.All(125), 10);
                        Cv2.Line(input, (int)minRectPoints[1].X, (int)minRectPoints[1].Y,
                            (int)minRectPoints[2].X, (int)minRectPoints[2].Y, Scalar.All(125), 10);
                        Cv2.Line(input, (int)minRectPoints[2].X, (int)minRectPoints[2].Y,
                            (int)minRectPoints[3].X, (int)minRectPoints[3].Y, Scalar.All(125), 10);
                        Cv2.Line(input, (int)minRectPoints[0].X, (int)minRectPoints[0].Y,
                            (int)minRectPoints[3].X, (int)minRectPoints[3].Y, Scalar.All(125), 10);
                        float angle = minRect.Angle;
                        OpenCvSharp.Point2f center = minRect.Center;
                        OpenCvSharp.Size2f outline = minRect.Size;
                        Cv2.Circle(input, new OpenCvSharp.Point((int)center.X, (int)center.Y), 20, Scalar.All(140), 20);
                        //MarkerCross(input, center.X, center.Y, 50);
                        displalyInfo.displayInfoMain("轮廓长度（点数）："+contours[i].Length.ToString("#0.00"));
                        displalyInfo.displayInfoMain("最小外接矩形旋转角度是：" + angle.ToString("#0.00"));
                        displalyInfo.displayInfoMain("最小外接矩形中心X Y是：" + center.X.ToString("#0.00") + "   " + center.Y.ToString("#0.00"));
                        displalyInfo.displayInfoMain("最小外接矩形宽度高度是：" + outline.Width.ToString("#0.00") + "   " + outline.Height.ToString("#0.00"));
                        minRectOutline[0] = outline.Width;
                        minRectOutline[1] = outline.Height;
                    }
                }
                if (haveRec == false)
                {
                    displalyInfo.displayInfoMain("没有找到矩形");
                    return false;
                }
                Cv2.PyrDown(copyMat, copyMat);
                Cv2.PyrDown(copyMat, copyMat);

                CircleSegment[] circleC = Cv2.HoughCircles(copyMat, HoughMethods.Gradient, 1, 50, 120, 100);
                for (int i = 0; i < circleC.Length; i++)
                {
                    circleCenter = circleC[i].Center;
                    Cv2.Circle(input, (int)circleC[i].Center.X * 4, (int)circleC[i].Center.Y * 4,
                        (int)circleC[i].Radius * 4, Scalar.All(125), 25, LineTypes.Link8, 0);
                    Cv2.Circle(input, (int)circleC[i].Center.X * 4, (int)circleC[i].Center.Y * 4,
                        (int)circleC[i].Radius / 50, Scalar.All(125), 5, LineTypes.Link8, 0);
                    opencvProc.MarkerCross(input, (int)circleC[i].Center.X*4, (int)circleC[i].Center.Y*4, 100);
                    Point2f circleToUp;
                    circleToUp.X = (int)circleC[i].Center.X * 4;
                    circleToUp.Y = (int)circleC[i].Center.Y * 4;
                    cir_Center = circleToUp;

                    displalyInfo.displayInfoMain("圆中心坐标是：  X " + circleToUp.X.ToString() + "  Y  " + circleToUp.Y.ToString());
                }
                if (circleC.Length == 0)
                {
                    displalyInfo.displayInfoMain("houghCircle没有找到圆");
                    return false;
                }
                if (angleHor > 45 && angleHor < 135)
                {
                    XcorZero = circleCenter.Y * 4 < recCenter.Y;
                }
                else
                {
                    XcorZero = circleCenter.X * 4 < recCenter.X;
                }

                //YcorZero = circleCenter.Y > recCenter.Y;
                if (XcorZero)
                {
                    if (angleHor >= 0 && angleHor <= 45)
                    {
                        RotateAngle = angleHor;
                    }
                    else if (angleHor > 45 && angleHor <= 135)
                    {
                        RotateAngle = 180 + angleHor;
                    }
                    else
                    {
                        RotateAngle = -180 + angleHor;
                    }
                    return true;
                }
                else
                {
                    if (angleHor >= 0 && angleHor <= 45)
                    {
                        RotateAngle = 180 + angleHor;

                    }
                    else if (angleHor > 45 && angleHor <= 135)
                    {
                        RotateAngle = angleHor;
                    }
                    else
                    {
                        RotateAngle = angleHor;
                    }
                    return true;
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("position异常："+ex.Message);
                return false;
            }


        }

        public static bool MarkerCross(Mat input,double centerX,double centerY,int crossLength)
        {
            try
            {
                int startX, endX, startY, endY;
                startX =(int) centerX - crossLength / 2;
                endX = (int)centerX + crossLength / 2;
                startY = (int)centerY - crossLength / 2;
                endY = (int)centerY + crossLength / 2;
                if (startX<0)
                {
                    startX = 0;
                }
                if (    endX>input.Width)
                {
                    endX = input.Width;
                }
                if (startY<0)
                {
                    startY = 0;
                }
                if (endY>input.Height)
                {
                    endY = input.Height;
                }
                Cv2.Line(input, new OpenCvSharp.Point(startX, centerY), new OpenCvSharp.Point(endX, centerY),Scalar.Red,10);
                Cv2.Line(input, new OpenCvSharp.Point(centerX,startY), new OpenCvSharp.Point(centerX,endY), Scalar.Red, 10);
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("MarkerCross 出错："+ex.Message);
                return false;
            }
        }
        public static bool MarkerCross(Mat input, OpenCvSharp.Point center, int crossLength)
        {
            try
            {
                int startX, endX, startY, endY;
                startX = (int)center.X - crossLength / 2;
                endX = (int)center.X + crossLength / 2;
                startY = (int)center.Y - crossLength / 2;
                endY = (int)center.Y + crossLength / 2;
                if (startX < 0)
                {
                    startX = 0;
                }
                if (endX > input.Width)
                {
                    endX = input.Width;
                }
                if (startY < 0)
                {
                    startY = 0;
                }
                if (endY > input.Height)
                {
                    endY = input.Height;
                }
                Cv2.Line(input, new OpenCvSharp.Point(startX, center.Y), new OpenCvSharp.Point(endX, center.Y), Scalar.Red, 10);
                Cv2.Line(input, new OpenCvSharp.Point(center.X,startY), new OpenCvSharp.Point(center.X,endY), Scalar.Red, 10);
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("MarkerCross 出错：" + ex.Message);
                return false;
            }
        }

        public static double PointToLine(OpenCvSharp.Point2f Apoint,OpenCvSharp.Point2f Bpoint,OpenCvSharp.Point2f distancePoint)
        {
            try
            {
                double a = Bpoint.Y - Apoint.Y;
                double b = Apoint.X - Bpoint.X;
                double c = Apoint.Y * Bpoint.X - Apoint.X - Bpoint.Y;
                if ((a*a+b*b)==0)
                {
                    return 0;
                }
                double d = Math.Abs((a * distancePoint.X + b * distancePoint.Y) / Math.Sqrt(a * a + b * b));
                return d;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("PointToLine 出错：" + ex.Message);
                return 0;
            }
        }

        public static bool DrawLine(Mat input,OpenCvSharp.Line2D vectorLine, OpenCvSharp.Scalar color)
        {
            try
            {
                //AX+BY+C=0;直线另一种表达 k=-A/B  C=-AX-BY
                //y=kx+b k为斜率 斜率等于切线与X轴的夹角，即tan(a)=k=-A/B;
                // k = Line2D.Vy/Line2D.Vx，b = Line2D.Y1 - k * Line2D.X1
                // 如果直线用 ρ=xcosθ+ysinθ 来表示， 那么 θ=arctank+π/2
                //Math.Atan2(y,x) y在前x在后  返回值为弧度
                double Vx = vectorLine.Vx;
                double Vy = vectorLine.Vy;
                double x0 = vectorLine.X1, y0 = vectorLine.Y1;

                double tho =Math.Atan2(Vy, Vx) + Math.PI / 2;
                double rho = y0 * Vx - x0 * Vy;

                if (tho < Math.PI / 4 || tho > 3* Math.PI / 4)
                {
                    OpenCvSharp.Point pt1=new OpenCvSharp.Point(rho / Math.Cos(tho), 0);
                    OpenCvSharp.Point pt2=new OpenCvSharp.Point((rho - input.Rows * Math.Sin(tho)) / Math.Cos(tho), input.Rows);
                    Cv2.Line(input, pt1, pt2, color, 1);
                }
                else
                {
                    OpenCvSharp.Point pt1 =new OpenCvSharp.Point(0, rho / Math.Sin(tho));
                    OpenCvSharp.Point pt2=new OpenCvSharp.Point(input.Cols, (rho - input.Cols *Math.Cos(tho)) / Math.Sin(tho));
                    Cv2.Line(input, pt1, pt2, Scalar.All(255), 1);
                }

                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("DrawLine 出错："+ex.Message);
                return false;
            }
        }

    }
}
